「資料重複」是常見且麻煩的問題,尤其是在 ETL Pipeline 或實時資料流匯入(如 Kafka Stream)時,重複資料會嚴重影響統計結果與查詢效率。ClickHouse 提供了一套簡單卻強大的去重機制:ReplacingMergeTree 儲存引擎。
本篇文章將帶你深入了解 ReplacingMergeTree 的運作原理、使用場景與 Best Practice。
ReplacingMergeTree 是 ClickHouse MergeTree 家族的一員(家族真熱鬧),它能在背景 Merge 操作時,自動根據指定欄位 (如 version 欄位) 將重複資料去除,保留最新版本或最先寫入的那一筆。
CREATE TABLE user_profiles
(
user_id UInt64,
profile_version UInt32,
name String,
email String
) ENGINE = ReplacingMergeTree(profile_version)
ORDER BY user_id;
profile_version
為版本欄位,決定在去重時保留最新版本。INSERT INTO user_profiles VALUES (1, 1, 'Alice', 'alice_v1@example.com');
INSERT INTO user_profiles VALUES (1, 2, 'Alice', 'alice_v2@example.com');
INSERT INTO user_profiles VALUES (2, 1, 'Bob', 'bob@example.com');
查詢時可能會看到重複資料,因為去重尚未透過 Merge 發生:
SELECT * FROM user_profiles WHERE user_id = 1;
結果:
user_id | profile_version | name | |
---|---|---|---|
1 | 1 | Alice | alice_v1@example.com |
1 | 2 | Alice | alice_v2@example.com |
進行 FINAL
查詢語法後( FINAL
確保查詢時「讀到最新去重後的結果」):
OPTIMIZE TABLE user_profiles FINAL;
SELECT * FROM user_profiles FINAL WHERE user_id = 1;
OPTIMIZE
:強制執行資料片段 (Data Parts) 合併動作,把分散的小 Data Parts 合併成大 Part,並同時觸發資料去重(ReplacingMergeTree)或聚合(SummingMergeTree)等邏輯。
實質影響的是磁碟上的 Data Parts 資料,合併結果是永久性(會寫入磁碟)。
再查詢結果只會剩下 version = 2
的那筆資料。
Primary Key
判斷的,因此建表時的 ORDER BY
欄位(也就是 Primary Key
)必須正確設計。ORDER BY
欄位無法唯一識別一筆記錄,則 ReplacingMergeTree
可能會保留錯誤的資料版本。ORDER BY (user_id, profile_version)
這種情況下,ReplacingMergeTree 無法自動去重,因為 Primary Key 已包含 version 值,會將每個版本當成不同資料。
正確設計應該是:
ORDER BY user_id
場景 | 說明 |
---|---|
Kafka / Stream 資料流重放去重 | 多次 Consume、資料重放(At-least-once 保證)情境下自動去重。 |
批次資料匯入過濾重複 | ETL 導入過程中重複載入相同資料,透過背景去重保證資料唯一性。 |
具版本控制的資料歷史維護 | 保留最新版本資料,版本號較小的資料會在合併過程中被去除。 |
資料補正修正 | 資料寫入後若有誤,透過補寫版本號較大的修正資料覆蓋錯誤記錄。 |
特性 | ReplacingMergeTree | AggregatingMergeTree |
---|---|---|
核心功能 | 根據 Primary Key 去重,保留 version 最大的資料 |
根據 AggregateFunction 資料型別進行合併彙總 |
版本欄位 | 可選,無指定時保留任一筆 | 無需版本欄位 |
適用場景 | 重複資料去除、最新版本資料保持 | 預先彙總的資料庫,如行為統計、即時計數 |
Merge 過程 | 合併時將相同主鍵的資料合併為一筆 | 合併時將 AggregateFunction 聚合運算結果計算出來 |
ReplacingMergeTree
是 背景合併去重。OPTIMIZE TABLE FINAL
來確保資料唯一。Primary Key
時,應僅包含「能唯一識別一筆邏輯記錄」的欄位,不要把 version
放進 ORDER BY
。ReplacingMergeTree
的寫入效能與 MergeTree
相近,因為去重是延遲處理的,不影響寫入吞吐量。ReplacingMergeTree
提供了一種無需複雜索引或額外處理邏輯即可實現資料去重的輕量解決方案,非常適合用於 「Data Stream 去重」、「批次匯入防重複」、「版本控制」 等場景。
然而,了解其 去重時機 與 Primary Key
設計要點 是使用這個引擎的關鍵。